@file:Suppress("unused", "UNUSED_PARAMETER", "NOTHING_TO_INLINE")

import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.reflect.KClass

/**************************************************/
/***** Extracted from 'classTransformations': *****/
/**************************************************/

class Class {
    fun f() = "Class.f"
    val p get() = "Class.p"
    override fun toString() = "Class"
}

enum class ClassToEnum {
    Foo,
    Bar,
    Baz
}

enum class ObjectToEnum {
    Foo,
    Bar
}

class EnumToClass {
    class Foo
    object Bar
    inner class Baz
}

object EnumToObject {
    class Foo
    object Bar
}

object ClassToObject
class ObjectToClass

interface ClassToInterface

class NestedObjectToCompanion1 {
    companion object {
        fun name() = "NestedObjectToCompanion1.Companion"
        override fun toString() = name()
    }
}

class NestedObjectToCompanion2 {
    companion object Foo {
        fun name() = "NestedObjectToCompanion2.Foo"
        override fun toString() = name()
    }
}

class CompanionToNestedObject1 {
    object Companion {
        fun name() = "CompanionToNestedObject1.Companion"
        override fun toString() = name()
    }
}

class CompanionToNestedObject2 {
    object Foo {
        fun name() = "CompanionToNestedObject2.Foo"
        override fun toString() = name()
    }
}

class CompanionAndNestedObjectsSwap {
    object Foo {
        fun name() = "Foo"
    }

    companion object Bar {
        fun name() = "Bar"
    }
}

class NestedClassContainer {
    fun name() = "NestedClassContainer"

    inner class NestedToInner {
        fun name() = this@NestedClassContainer.name() + ".NestedToInner"
        override fun toString() = name()

        inner class /*object*/ Object {
            fun name() = this@NestedToInner.name() + ".Object"
            override fun toString() = name()
        }

        inner class /*companion object*/ Companion {
            fun name() = this@NestedToInner.name() + ".Companion"
            override fun toString() = name()
        }

        inner class /*class*/ Nested {
            fun name() = this@NestedToInner.name() + ".Nested"
            override fun toString() = name()
        }

        inner class Inner {
            fun name() = this@NestedToInner.name() + ".Inner"
            override fun toString() = name()
        }
    }
}

class InnerClassContainer {
    fun name() = "InnerClassContainer"

    class InnerToNested {
        fun name() = "InnerClassContainer.InnerToNested"
        override fun toString() = name()

        object Object {
            fun name() = "InnerClassContainer.InnerToNested.Companion"
            override fun toString() = name()
        }

        companion object Companion {
            fun name() = "InnerClassContainer.InnerToNested.Companion"
            override fun toString() = name()
        }

        class Nested {
            fun name() = "InnerClassContainer.InnerToNested.Nested"
            override fun toString() = name()
        }

        inner class Inner {
            fun name() = this@InnerToNested.name() + ".Inner"
            override fun toString() = name()
        }
    }
}

annotation class AnnotationClassWithChangedParameterType(val x: /*Int*/ String)
/*annotation*/ class AnnotationClassThatBecomesRegularClass(val x: Int) { override fun toString() = "AnnotationClassThatBecomesRegularClass[x=$x]" }
//annotation class AnnotationClassThatDisappears(val x: Int)
annotation class AnnotationClassWithRenamedParameters(val xi: Int, val xs: String)
annotation class AnnotationClassWithReorderedParameters(val s: String, val i: Int)
annotation class AnnotationClassWithNewParameter(val i: Int, val s: String = "Apple")

class ValueToClass(val x: Int)
value class ClassToValue(val x: Int)

/*data*/ class DataToClass(val x: Int, val y: Int)

abstract class ClassToAbstractClass {
    abstract var name: String
    fun getGreeting() = "Hello, $name!"
}

//class RemovedClass {
//    fun f() = "FAIL: RemovedClass.f"
//    val p get() = "FAIL: RemovedClass.p"
//}
enum class EnumClassWithDisappearingEntry { UNCHANGED, /*REMOVED*/ }

object PublicTopLevelLib1 {
    private annotation class AnnotationClassThatBecomesPrivate
    private class ClassThatBecomesPrivate
    private enum class EnumClassThatBecomesPrivate { ENTRY }
}

interface XAnswer { fun answer(): Int }
interface XAnswerDefault { fun answer(): Int /*= 42*/ }
interface XFunction1 { fun function1(): Int }
interface XFunction1Default { fun function1(): Int = 42 }
interface XFunction2 { fun function2(): Int }
interface XFunction2Default { fun function2(): Int = -42 }
interface XProperty1 { val property1: Int }
interface XProperty1Default { val property1: Int get() = 42 }
interface XProperty2 { val property2: Int }
interface XProperty2Default { val property2: Int get() = 42 }

/*fun*/ interface FunctionalInterfaceToInterface : XAnswer

/*****************************************************/
/***** Extracted from 'functionTransformations': *****/
/*****************************************************/

object Functions {
    @Suppress("RedundantSuspendModifier") suspend fun <R> wrapCoroutine(coroutine: suspend () -> R): R = coroutine.invoke()
    fun suspendToNonSuspendFunction(x: Int): Int = -x
    suspend fun nonSuspendToSuspendFunction(x: Int): Int = wrapCoroutine { -x }

    inline fun inlineLambdaToNoinlineLambda(x: Int, noinline lambda: (Int) -> String): String = "Functions.inlineLambdaToNoinlineLambda($x) { ${lambda(x * 2)} }"
    inline fun inlineLambdaToCrossinlineLambda(x: Int, crossinline lambda: (Int) -> String): String = "Functions.inlineLambdaToCrossinlineLambda($x) { ${lambda(x * 2)} }"
}

open class OpenClass {
    inline fun openNonInlineToInlineFunction(x: Int): String = "OpenClassV2.openNonInlineToInlineFunction($x)"
    inline fun openNonInlineToInlineFunctionWithDelegation(x: Int): String = "OpenClassV2.openNonInlineToInlineFunctionWithDelegation($x)"
    inline fun newInlineFunction1(x: Int): String = "OpenClassV2.newInlineFunction1($x)"
    inline fun newInlineFunction2(x: Int): String = "OpenClassV2.newInlineFunction2($x)"
    fun newNonInlineFunction(x: Int): String = "OpenClassV2.newNonInlineFunction($x)"

    fun newInlineFunction1Caller(x: Int): String = newInlineFunction1(x)
    fun newInlineFunction2Caller(x: Int): String = newInlineFunction2(x)
    fun newNonInlineFunctionCaller(x: Int): String = newNonInlineFunction(x)
}

/********************************************/
/***** Extracted from 'removeCallable': *****/
/********************************************/

//fun removedFunction(): String = "FAIL: removedFunction"
//val removedProperty: String get() = "FAIL: removedProperty"

/*****************************************/
/***** Extracted from 'removeClass': *****/
/*****************************************/

//abstract class RemovedAbstractClass {
//    abstract fun abstractFun(): String
//    open fun openFun(): String = "RemovedAbstractClass.openFun"
//    fun finalFun(): String = "RemovedAbstractClass.finalFun"
//    abstract val abstractVal: String
//    open val openVal: String get() = "RemovedAbstractClass.openVal"
//    val finalVal: String get() = "RemovedAbstractClass.finalVal"
//}

//interface RemovedInterface {
//    fun abstractFun(): String
//    fun abstractFunWithDefaultImpl(): String = "RemovedInterface.abstractFunWithDefaultImpl"
//    val abstractVal: String
//    val abstractValWithDefaultImpl: String get() = "RemovedInterface.abstractValWithDefaultImpl"
//}

//open class RemovedOpenClass {
//    open fun openFun(): String = "RemovedOpenClass.openFun"
//    fun finalFun(): String = "RemovedOpenClass.finalFun"
//    open val openVal: String get() = "RemovedOpenClass.openVal"
//    val finalVal: String get() = "RemovedOpenClass.finalVal"
//}

/***********************************************/
/***** Extracted from 'inheritanceIssues': *****/
/***********************************************/

abstract class InterfaceToAbstractClass
open class InterfaceToOpenClass
class InterfaceToFinalClass
annotation class InterfaceToAnnotationClass
object InterfaceToObject
enum class InterfaceToEnumClass
value class InterfaceToValueClass(val x: Int)
data class InterfaceToDataClass(val x: Int)

final class OpenClassToFinalClass(val x: Int)
annotation class OpenClassToAnnotationClass(val x: Int)
object OpenClassToObject { val x: Int = 42 }
enum class OpenClassToEnumClass(val x: Int)
value class OpenClassToValueClass(val x: Int)
data class OpenClassToDataClass(val x: Int)
interface OpenClassToInterface { val x: Int }

abstract class InterfaceToAbstractClass1
abstract class InterfaceToAbstractClass2
abstract class AbstractClass

abstract class AbstractClassWithChangedConstructorSignature(name: String, city: String) {
    val greeting = "Hello, $name from $city!"
}

open class OpenClassWithChangedConstructorSignature(name: String, city: String) {
    val greeting = "Hello, $name from $city!"
}

open class SuperSuperClass {
    open fun inheritsFrom() = "SuperSuperClass -> Any"
}
open class SuperClass : SuperSuperClass() {
    override fun inheritsFrom() = "SuperClass -> " + super.inheritsFrom()
}
class SuperSuperClassReplacedBySuperClass : /*SuperSuperClass()*/ SuperClass() {
    override fun inheritsFrom() = "SuperSuperClassReplacedBySuperClass -> " + super.inheritsFrom()
}
class SuperClassReplacedBySuperSuperClass : /*SuperClass()*/ SuperSuperClass() {
    override fun inheritsFrom() = "SuperClassReplacedBySuperSuperClass -> " + super.inheritsFrom()
}

/*************************************/
/***** Extracted from 'kt73511': *****/
/*************************************/

@Target(CLASS)
@Retention(BINARY)
public annotation class MyAnnotationMarker(
    vararg val markerClass: KClass<out Annotation>,
)

/*****************************************************/
/***** Extracted from 'propertyTransformations': *****/
/*****************************************************/

open class OpenClassWithProperties {
    @Suppress("MemberVisibilityCanBePrivate")
    var lastRecordedState: String = ""

    inline var openNonInlineToInlineProperty: String
        get() = "OpenClassWithPropertiesV2.openNonInlineToInlineProperty"
        set(value) { lastRecordedState = "OpenClassWithPropertiesV2.openNonInlineToInlineProperty=$value" }

    inline var openNonInlineToInlinePropertyWithDelegation: String
        get() = "OpenClassWithPropertiesV2.openNonInlineToInlinePropertyWithDelegation"
        set(value) { lastRecordedState = "OpenClassWithPropertiesV2.openNonInlineToInlinePropertyWithDelegation=$value" }

    inline var newInlineProperty1: String
        get() = "OpenClassWithPropertiesV2.newInlineProperty1"
        set(value) { lastRecordedState = "OpenClassWithPropertiesV2.newInlineProperty1=$value" }

    inline var newInlineProperty2: String
        get() = "OpenClassWithPropertiesV2.newInlineProperty2"
        set(value) { lastRecordedState = "OpenClassWithPropertiesV2.newInlineProperty2=$value" }

    var newNonInlineProperty: String
        get() = "OpenClassWithPropertiesV2.newNonInlineProperty"
        set(value) { lastRecordedState = "OpenClassWithPropertiesV2.newNonInlineProperty=$value" }

    fun newInlineProperty1Reader(): String = newInlineProperty1
    fun newInlineProperty2Reader(): String = newInlineProperty2
    fun newNonInlinePropertyReader(): String = newNonInlineProperty

    fun newInlineProperty1Writer(value: String) { newInlineProperty1 = value }
    fun newInlineProperty2Writer(value: String) { newInlineProperty2 = value }
    fun newNonInlinePropertyWriter(value: String) { newNonInlineProperty = value }
}
